#ifndef HTTP_H
#define HTTP_H
#include "common.h"
#include "header.h"
#include "thread.h"
#include "cache_file.h"

typedef struct cache_control {
	int max_age;
	int s_maxage;
	int public; /* The document is cacheable by any cache. */
	int private; /* The document is not cacheable by a shared cache. */
	int no_store;
	int no_cache;  /* can cache, but must revalidate */
	int only_if_cached; /* The client wants a copy only if it is in the cache */
	int min_stale;
	int max_stale; 
	int min_fresh;	
	int no_transform; /* Do not convert the entity-body. Useful for applications that require that the message received is exactly what was sent by the server. */
	int proxy_revalidate; /* Client must revalidate data except for private client caches. Public caches must verify the status of stale documents. Like must-revalidate, excluding private caches. */
	int must_revalidate; /* The cache must verify the status of stale documents, i.e., the cache cannot blindly use a document that has expired */
}cache_control_t;

enum CONN_STATE {
	TCP_NONE = -1,
	TCP_MISS = 0,
	TCP_HIT = 1, 
	TCP_REVALIDATE,
	TCP_REFRESH_HIT, 
	TCP_REFRESH_MISS,
	TCP_REFRESH_ERROR,
	TCP_SHM_HIT, 
	TCP_MEM_HIT,
};

enum DATA_SEND_STATE {
	DATA_NONE, 
	DATA_REPLY_IN,
	DATA_MEM_CACHE, 
	DATA_SHM_CACHE, 
	DATA_DISK,
};

typedef struct {
	aint low;
	aint high;
	int shm_fd;
	int size;
	void *start;
}mmap_t;

typedef struct {
	aint header_size;
	aint body_size;
	aint header_out;
	aint body_out; 
	aint body_in;
	int parsed;
	int header_send;
	int statu;
	http_version_t version;
	header_t *headers;
	string *in;  /* from socket or disk */
	int disk;    /* fd which is open with disk file */
	struct {
		aint offset;
	}swapout;
	/* read from disk. Data can store in /dev/shm or reply->in */
	struct {
		aint offset;
	}swapin;
	mmap_t map;
	cache_control_t cc;
}reply_t;

typedef struct {
	string *in;
	char *url_path;
	char *host;
	int port;
	int proto;
	header_t *headers;
	
	http_version_t version;
	method_t method;
	cache_control_t cc;
	/* log */
	int log_state;
}request_t;

typedef struct {
	int cfd; /* client fd */
    struct in_addr client_addr;
	struct event client_event;
	request_t *request;
	
	int sfd; /* server fd */
    struct sockaddr_in server_addr;
	struct event server_event;
	reply_t *reply;

	/* thread */
	thread_t *thread;
	struct event timeout_event;
	struct event timer;
	cache_file_t *cache;
}conn_t;	

extern conn_t *conn_new(int cfd, short cfl, PF *ch, void *arg, struct in_addr *client_addr, struct event_base *base, thread_t *thread) ;
extern void conn_free(conn_t *con);
extern void conn_timeout_set(struct event *ev, PF *handler, void *arg, int timeout, struct event_base *base);
extern void conn_timeout_handle(int fd, short flag, void *arg);


extern void http_request_read(int fd, short flag, void *arg);
/* event handler */
extern int event_update(struct event *ev, int fd, short new_flag, PF *handler, void *arg);
extern int timeout_update(struct event *ev, PF *handler, void *arg, int timeout);
extern int timer_update(struct event *ev, PF *handler, void *arg, int sec, int usec);
extern char *conn_state_string(int state);
/* data search */
extern int mem_cache_find(conn_t *con, cache_file_t *cache);
extern int shm_cache_find(conn_t *con, cache_file_t *cache);
extern int disk_find(conn_t *con, cache_file_t *cache);
extern int disk_map(reply_t *rep, string *file, aint low, aint high);
extern void disk_map_reset(mmap_t *map);
extern char *DATA_SEND_STATE_STRING(int state);
#endif
